package com.xiaoshuidi.cloud.module.finance.service.finance.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.core.KeyValue;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.redis.sequence.TimebaseSequenceGenerator;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.module.finance.controller.admin.finance.vo.transfer.FinancePaymentChangeLogPageReqVO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.finance.vo.transfer.FinancePaymentChangeLogVO;
import com.xiaoshuidi.cloud.module.finance.controller.admin.finance.vo.transfer.FinancePaymentChangeUpdateVO;
import com.xiaoshuidi.cloud.module.finance.convert.finance.FinanceConvert;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinanceBankTransferDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinancePaymentChangeLogDO;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.finance.FinanceBankTransferMapper;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.finance.FinancePaymentChangeLogMapper;
import com.xiaoshuidi.cloud.module.finance.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.finance.enums.order.FinanceCommonStatusEnum;
import com.xiaoshuidi.cloud.module.finance.service.finance.FinancePaymentChangeLogService;
import com.xiaoshuidi.cloud.module.system.api.user.AdminUserApi;
import com.xiaoshuidi.cloud.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class FinancePaymentChangeLogServiceImpl implements FinancePaymentChangeLogService {
    @Resource
    private FinancePaymentChangeLogMapper financePaymentChangeLogMapper;

    @Resource
    private FinanceBankTransferMapper financeBankTransferMapper;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private TimebaseSequenceGenerator timebaseSequenceGenerator;


    @Override
    public PageResult<FinancePaymentChangeLogVO> selectLogPage(FinancePaymentChangeLogPageReqVO vo) {
        Page<FinancePaymentChangeLogVO> pageList =
                financePaymentChangeLogMapper.selectLogPage(new Page<FinancePaymentChangeLogDO>(vo.getPageNo(),
                        vo.getPageSize()), vo);
        AtomicInteger index = new AtomicInteger((vo.getPageNo() - 1) * vo.getPageSize() + 1);
        pageList.getRecords().stream().forEach
                (m -> {
                    m.setSerialNumber(index.getAndIncrement());
                });
        return new PageResult<FinancePaymentChangeLogVO>(pageList.getRecords(), pageList.getTotal());
    }

    @Override
    public FinancePaymentChangeLogVO getById(Long id) {
        return financePaymentChangeLogMapper.getById(id);
    }

    @Override
    public List<FinancePaymentChangeLogVO> getByIds(List<Long> ids) {
        return financePaymentChangeLogMapper.getByIds(ids);
    }

    @Override
    public FinancePaymentChangeUpdateVO getByIdUpdateView(Long id) {
        FinancePaymentChangeLogDO financePaymentChangeLogDO = financePaymentChangeLogMapper.selectById(id);
        //变更单不存在
        if (ObjectUtil.isNull(financePaymentChangeLogDO)) {
            throw new ServiceException(ErrorCodeConstants.PAYMENT_CHANGE_LOG_NOT_EXISTS);
        }
        return FinanceConvert.INSTANCE.convertLogDo(financePaymentChangeLogDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changePaymentTransfer(FinancePaymentChangeUpdateVO changeUpdateVO) {
        FinancePaymentChangeLogDO financePaymentChangeLogDO =
                financePaymentChangeLogMapper.selectById(changeUpdateVO.getId());
        //变更单不存在
        if (ObjectUtil.isNull(financePaymentChangeLogDO)) {
            throw new ServiceException(ErrorCodeConstants.PAYMENT_CHANGE_LOG_NOT_EXISTS);
        }
        if (financePaymentChangeLogDO.getIsChange() == 1) {
            throw new ServiceException(ErrorCodeConstants.PAYMENT_CHANGE_LOG_CORRECTED);
        }

        FinanceBankTransferDO financeBankTransferDO =
                financeBankTransferMapper.selectById(financePaymentChangeLogDO.getTransId());
        //仅能变更失败情况下
        if (!FinanceCommonStatusEnum.FAILURE.name().equals(financeBankTransferDO.getStatus())) {
            throw new ServiceException(ErrorCodeConstants.PAYMENT_CHANGE_LOG_CORRECTED.getCode(), "仅能变更已失败打款项");
        }
        if (financeBankTransferDO == null) {
            throw new ServiceException(ErrorCodeConstants.FINANCE_BANK_TRANSFER_NOT_EXISTS);
        }
        AdminUserRespDTO user;
        try {
            CommonResult<AdminUserRespDTO> loginUser = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
            loginUser.checkError();
            user = loginUser.getData();
        } catch (Exception e) {
            log.error("获取用户信息失败", e);
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
        }

        String number = "FK" + timebaseSequenceGenerator.YYYYMMDDHHMMSS.next("lease:transfer:number", "%04d");
        //原有写入日志
        List<Object> logs = financeBankTransferDO.getLogs();
        if (CollectionUtils.isEmpty(logs)) {
            logs = new ArrayList<>(0);
        }
        String datetime = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        String logFmt = "%s(%s)编辑%s由\"%s\"修改为\"%s\"";
        if (StringUtils.hasText(financePaymentChangeLogDO.getPayeeName())
                && !Objects.equals(financeBankTransferDO.getPayeeName(), changeUpdateVO.getPayeeName())) {
            logs.add(new KeyValue<>(datetime, String.format(logFmt, user.getNickname(), user.getMobile(), "收款人",
                    financeBankTransferDO.getPayeeName(),
                    changeUpdateVO.getPayeeName())));
        }
        if (StringUtils.hasText(financePaymentChangeLogDO.getPayeeBankAccount())
                && !Objects.equals(financeBankTransferDO.getPayeeBankAccount(), changeUpdateVO.getPayeeBankAccount())) {
            logs.add(new KeyValue<>(datetime, String.format(logFmt, user.getNickname(), user.getMobile(), "银行卡号",
                    financeBankTransferDO.getPayeeBankAccount(),
                    changeUpdateVO.getPayeeBankAccount())));
        }
        if (StringUtils.hasText(financePaymentChangeLogDO.getPayeeBank())
                && !Objects.equals(financeBankTransferDO.getPayeeBank(), changeUpdateVO.getPayeeBank())) {
            logs.add(new KeyValue<>(datetime, String.format(logFmt, user.getNickname(), user.getMobile(), "所属银行",
                    financeBankTransferDO.getPayeeBank(),
                    changeUpdateVO.getPayeeBank())));
        }
        if (StringUtils.hasText(financePaymentChangeLogDO.getPayeeBankBranch())
                && !Objects.equals(financeBankTransferDO.getPayeeBankBranch(), changeUpdateVO.getPayeeBankBranch())) {
            logs.add(new KeyValue<>(datetime, String.format(logFmt, user.getNickname(), user.getMobile(), "所属支行",
                    financeBankTransferDO.getPayeeBankBranch(),
                    changeUpdateVO.getPayeeBankBranch())));
        }

        if (StringUtils.hasText(financePaymentChangeLogDO.getPayeeMobile())
                && !Objects.equals(financeBankTransferDO.getPayeeMobile(), changeUpdateVO.getPayeeMobile())) {
            logs.add(new KeyValue<>(datetime, String.format(logFmt, user.getNickname(), user.getMobile(), "收款通知号码",
                    financeBankTransferDO.getPayeeMobile(),
                    changeUpdateVO.getPayeeMobile())));
        }

        logs.add(new KeyValue<>(datetime, String.format("%s(%s)变更打款信息, 原单号:%s", user.getNickname(), user.getMobile(),
                financeBankTransferDO.getNumber())));
        FinanceBankTransferDO.FinanceBankTransferDOBuilder update = FinanceBankTransferDO.builder()
                .id(financePaymentChangeLogDO.getTransId().intValue())
                .bizDate(LocalDate.now())
                .number(number)
                .payeeName(changeUpdateVO.getPayeeName())
                .payeeBankAccount(changeUpdateVO.getPayeeBankAccount())
                .payeeBank(changeUpdateVO.getPayeeBank())
                .payeeBankBranch(changeUpdateVO.getPayeeBankBranch())
                .payeeBankCode(changeUpdateVO.getPayeeBankCode())
                .payeeBankProvince(changeUpdateVO.getPayeeBankProvince())
                .payeeBankCity(changeUpdateVO.getPayeeBankCity())
                .payeeMobile(changeUpdateVO.getPayeeMobile())
                //已更正
                .isChange(1)
                .logs(logs);
        financeBankTransferMapper.updateById(update.build());

        FinancePaymentChangeLogDO changeLogDO = FinancePaymentChangeLogDO.builder()
                .id(changeUpdateVO.getId())
                .afterNumber(number)
                .afterPayeeName(changeUpdateVO.getPayeeName())
                .afterPayeeBankAccount(changeUpdateVO.getPayeeBankAccount())
                .afterPayeeBank(changeUpdateVO.getPayeeBank())
                .afterPayeeBankBranch(changeUpdateVO.getPayeeBankBranch())
                .afterPayeeBankCode(changeUpdateVO.getPayeeBankCode())
                .afterPayeeBankProvince(changeUpdateVO.getPayeeBankProvince())
                .afterPayeeBankCity(changeUpdateVO.getPayeeBankCity())
                .afterPayeeMobile(changeUpdateVO.getPayeeMobile())
                .isChange(1)
                //变更人信息
                .changeOperator(user.getNickname())
                .changeOperatorId(user.getId())
                .build();
        financePaymentChangeLogMapper.updateById(changeLogDO);
        return true;
    }
}
